#include "Log.hpp"
#include "daemonize.hpp"
#include "Guard.hpp"
#include "util.hpp"
#include "Task.hpp"
#include "threadpool.hpp"

#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

// ./server port
class Server{
public:
  Server(uint16_t port, std::string ip = ""):_port(port), _ip(ip), instance(nullptr)
  {}
  ~Server()
  {}
public:
  void init()
  {
    //创建套接字
    _sockfd = socket(AF_INET, SOCK_STREAM, 0);
    //填写socket
    struct sockaddr_in local;
    bzero(&local,sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    _ip.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : inet_aton(_ip.c_str(),&local.sin_addr);
    //绑定端口号
    if(bind(_sockfd, (const struct sockaddr*)&local, sizeof(local)) < 0)
    {
      logMessage(FATAL, "bind: %s", strerror(errno));
      exit(1);
    }
    logMessage(DEBUG, "bind success");
    //tcp需要监听然后连接双方
    if(listen(_sockfd, 5) < 0)//5为最大连接数
    {
      logMessage(FATAL,"listn: %s", strerror(errno));
      exit(LISTEN_ERR);
    }
    logMessage(DEBUG, "listen sucess");
    //等待别人连接
  }
  void loop()
  {
    instance = ThreadPool<Task>::getInstance();
    instance->start();
    while(true)
    {
      struct sockaddr_in peer;
      socklen_t len = sizeof(peer);
      //获取连接
      int serviceSock = accept(_sockfd, (struct sockaddr*)&peer, &len);
      if(serviceSock < 0)
      {
        logMessage(WARINING, "accept: %s[%d]", strerror(errno), serviceSock);
        continue;
      }
      logMessage(DEBUG,"accept success %d",serviceSock);
      //记录客户端数据
      uint32_t peerPort = ntohs(peer.sin_port);
      std::string peerIp = inet_ntoa(peer.sin_addr);
      //生成任务并交给线程池
      Task t(serviceSock, peerPort, peerIp);
      instance->push(t);

    }//while
  }
private:
  int _sockfd;
  uint16_t _port;
  std::string _ip;
  ThreadPool<Task> *instance;
};

int main(int argc, char *argv[])
{
  if(argc != 2 && argc != 3)
  {
    logMessage(FATAL,"\n\t ./server port ip");
    exit(1);
  }

  uint16_t port = atoi(argv[1]);
  std::string ip;
  if(argc == 3)
  {
    ip = argv[2];
  }
  
  Server service(port,ip);
  service.init();
  service.loop();

  return 0;
}
